package com.michael.demos.base.thread.juc.lock;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class MutexAdderMain {

	public static void main(String[] args) {

		long nanoTimeStart = System.nanoTime();

		int threadCount = 5000;
		int addCount = 10000;

		MutexAdder adder = new MutexAdder();

		CountDownLatch countDownLatch = new CountDownLatch(threadCount);

		ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);

		for (int i = 0; i < threadCount; i++) {
			threadPool.submit(() -> {
				for (int j = 0; j < addCount; j++) {
					adder.increase();
				}
				countDownLatch.countDown();
			});
		}

		try {
			countDownLatch.await();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println("count:" + adder.getCounter());

		// 皮秒
		long picosecond = 1L;
		long nanoTimeEnd = System.nanoTime();
		// 纳秒
		long nanoTimeCost = nanoTimeEnd - nanoTimeStart;
		// 微秒
		long microTimeCost = nanoTimeCost / 1000;
		// 毫秒
		long milliTimeCost = microTimeCost / 1000;
		System.out.println(nanoTimeCost);
		System.out.println(microTimeCost);
		System.out.println(milliTimeCost);

		threadPool.shutdown();
	}
}

class MutexAdder {

	private volatile int counter;
	private final MutexLock lock;

	public MutexAdder() {
		lock = new MutexLock();
	}

	public void increase() {
		lock.lock();
		try {
			counter++;
		} finally {
			lock.unlock();
		}
	}

	public int getCounter() {
		return this.counter;
	}
}


/**
 * 类功能描述:
 * <pre>
 *   AbstractQueuedSynchronizer 注释中的用例 —— 不可重入的互斥锁实现
 *   0表示解锁状态，1表示锁定状态
 * </pre>
 *
 * @author Michael
 * @version 1.0
 * @date 2020/8/13 15:12
 */
class MutexLock implements Lock, java.io.Serializable {

	private final Sync sync = new Sync();

	@Override
	public void lock() {
		sync.acquire(1);
	}

	@Override
	public boolean tryLock() {
		return sync.tryAcquire(1);
	}

	@Override
	public void unlock() {
		sync.release(1);
	}

	@Override
	public Condition newCondition() {
		return sync.newCondition();
	}

	public boolean isLocked() {
		return sync.isHeldExclusively();
	}

	public boolean hasQueuedThreads() {
		return sync.hasQueuedThreads();
	}

	@Override
	public void lockInterruptibly() throws InterruptedException {
		sync.acquireInterruptibly(1);
	}

	@Override
	public boolean tryLock(long timeout, TimeUnit unit)
			throws InterruptedException {
		return sync.tryAcquireNanos(1, unit.toNanos(timeout));
	}


	/** 内部帮助类 */
	private static class Sync extends AbstractQueuedSynchronizer {
		// 当前是否为锁定状态
		@Override
		protected boolean isHeldExclusively() {
			return getState() == 1;
		}

		/** 尝试在独占模式获取锁 */
		@Override
		public boolean tryAcquire(int acquires) {
			if (getExclusiveOwnerThread() == Thread.currentThread()) {
				return true;
			}
			if (compareAndSetState(0, 1)) {
				setExclusiveOwnerThread(Thread.currentThread());
				return true;
			}
			return false;
		}

		/** 尝试释放锁 */
		@Override
		protected boolean tryRelease(int releases) {
			if (getState() == 0) {
				throw new IllegalMonitorStateException();
			}
			setExclusiveOwnerThread(null);
			setState(0);
			return true;
		}

		/** 提供条件 */
		Condition newCondition() {
			return new AbstractQueuedSynchronizer.ConditionObject();
		}

		/** 反序列化正确 */
		private void readObject(ObjectInputStream s)
				throws IOException, ClassNotFoundException {
			s.defaultReadObject();
			setState(0); // reset to unlocked state
		}
	}
}